package com.ym521.logdog.engine

import android.content.Context
import android.content.Intent
import android.widget.Toast
import androidx.core.content.FileProvider
import com.ym521.logdog.LogDog
import com.ym521.logdog.core.DefaultLogDogConfig
import com.ym521.logdog.core.IPrintLogEngine
import com.ym521.logdog.core.IDiskLogEngine
import com.ym521.logdog.core.IJsonEngine
import com.ym521.logdog.core.ILogDogEngine
import com.ym521.logdog.utils.LogFormatUtil
import java.io.File
import java.text.SimpleDateFormat
import java.util.*

/**
 * logdog(日志狗)
 * 日志狗核心引擎
 * 实现对日志信息的分发
 */
internal class LogDogEngine private constructor(private val jsonEngine: IJsonEngine) :
    ILogDogEngine {
    private lateinit var logPrinter: IPrintLogEngine
    private lateinit var logDiskWrite: IDiskLogEngine

    private constructor(mContext: Context, jsonEngine: IJsonEngine) : this(jsonEngine) {
        initPrintLogEngine()
        initDiskLogWriteEngine(mContext)
    }

    private fun initPrintLogEngine() {
        logPrinter = PrintLogEngine.build()
    }

    private fun initDiskLogWriteEngine(mContext: Context) {
        logDiskWrite = DiskLogEngine.build(mContext)
    }

    override fun <T> debug(tag: String, msg: T) {
        val msgContent = toMsgContent(msg)
        logDogEnable(DEBUG, tag, msgContent)
    }

    override fun debug(tag: String, msgFormat: String, vararg objs: Any) {
        logDogEnableFormat(DEBUG, tag, msgFormat, *objs)
    }

    override fun <T> info(tag: String, msg: T) {
        val msgContent = toMsgContent(msg)
        logDogEnable(INFO, tag, msgContent)
    }

    override fun info(tag: String, msgFormat: String, vararg objs: Any) {
        logDogEnableFormat(INFO, tag, msgFormat, *objs)
    }

    override fun <T> warn(tag: String, msg: T) {
        val msgContent = toMsgContent(msg)
        logDogEnable(WARN, tag, msgContent)
    }

    override fun warn(tag: String, msgFormat: String, vararg objs: Any) {
        logDogEnableFormat(WARN, tag, msgFormat, *objs)
    }

    override fun <T> error(tag: String, msg: T) {
        val msgContent = toMsgContent(msg)
        logDogEnable(ERROR, tag, msgContent)
    }

    override fun error(tag: String, msgFormat: String, vararg objs: Any) {
        logDogEnableFormat(ERROR, tag, msgFormat, *objs)
    }

    override fun <T> custom(priority: Int, tag: String, msg: T, printer: Boolean, write: Boolean) {
        val msgContent = toMsgContent(msg)
        logDogCustomEnable(printer, write, priority, tag, msgContent)
    }

    override fun custom(
        printer: Boolean,
        write: Boolean,
        priority: Int,
        tag: String,
        msgFormat: String,
        vararg objs: Any
    ) {
        logDogCustomEnableFormat(printer, write, priority, tag, msgFormat, *objs)
    }

    override fun shareLogFile(mContext: Context, type: Int) {
        if (!DefaultLogDogConfig.isWriteLogFileEnable) return
        val dateFormatFile = SimpleDateFormat("yyyy-MM-dd")
        val currentDate = dateFormatFile.format(Calendar.getInstance().time)
        //目录地址
        val fileParentPath = if (DefaultLogDogConfig.logFileShow) {
            mContext.getExternalFilesDir("logdog")?.absolutePath
        } else {
            mContext.getDir("logdog", Context.MODE_PRIVATE).absolutePath
        }
        val filePath = when (type) {
            LogDog.LOGFILE -> fileParentPath + "/${currentDate}.log"
            LogDog.CRASHFILE ->fileParentPath + "/crash_${currentDate}.log"
            else -> fileParentPath + "/${currentDate}.log"
        }
        if (filePath.isNotBlank()) {
            shareFile(mContext, filePath)
        }
    }

    override fun crashLog(tag: String, msgFormat: String, vararg objs: Any) {
        logDogEnableFormat(CRASH, tag, msgFormat, *objs)
    }

    private fun shareFile(mContext: Context, filePath: String) {
        val file = File(filePath)
        if (!file.exists()) return
        val intent = Intent(Intent.ACTION_SEND)
        intent.flags = Intent.FLAG_ACTIVITY_NEW_TASK
        val uri = FileProvider.getUriForFile(mContext, mContext.packageName + ".fileshare", file)
        intent.putExtra(Intent.EXTRA_STREAM, uri)
        intent.type = "text/plain" //分享文件类型
        mContext.startActivity(Intent.createChooser(intent, "分享日志"))
    }

    /**
     * 泛型处理
     * 转String 输出
     */
    private fun <T> toMsgContent(msg: T): String {
        val msgContent = when (msg) {
            is String -> msg
            is Char -> "$msg"
            is Int -> "$msg"
            is Byte -> "$msg"
            is Short -> "$msg"
            is Long -> "$msg"
            is Boolean -> "$msg"
            is Double -> "$msg"
            is Float -> "$msg"
            else ->
                jsonEngine.toJSON(msg as Any)
        }
        return msgContent
    }

    /**
     * 携带占位符% 的log 处理
     */
    private fun logDogEnableFormat(
        priority: Int,
        tag: String,
        msgFormat: String,
        vararg objArray: Any
    ) {
        val jsonArray = Array(objArray.size) { "" }
        try {
            for (index in objArray.indices) {
                jsonArray[index] = toMsgContent(objArray[index])
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        val msgContent = LogFormatUtil.toLogContent(msgFormat, *jsonArray)
        logDogHandlers(priority, tag, msgContent)
    }

    /**
     * 自定义 Log
     */
    private fun logDogCustomEnableFormat(
        printer: Boolean,
        write: Boolean,
        priority: Int,
        tag: String,
        msgFormat: String,
        vararg objArray: Any
    ) {
        val jsonArray = Array(objArray.size) { "" }
        try {
            for (index in objArray.indices) {
                jsonArray[index] = toMsgContent(objArray[index])
            }
        } catch (e: Exception) {
            e.printStackTrace()
        }
        val msgContent = LogFormatUtil.toLogContent(msgFormat, *jsonArray)
        logDogCustomHandlers(printer, write, priority, tag, msgContent)

    }

    /**
     * 正常log 处理
     */
    private fun logDogEnable(priority: Int, tag: String, msg: String) {
        val msgContent = toMsgContent(msg)
        logDogHandlers(priority, tag, msgContent)
    }

    /**
     * 自定义log 处理
     */
    private fun logDogCustomEnable(
        printer: Boolean, write: Boolean, priority: Int, tag: String, msg: String
    ) {
        val msgContent = toMsgContent(msg)
        logDogCustomHandlers(printer, write, priority, tag, msgContent)
    }

    private fun logDogHandlers(priority: Int, tag: String, msg: String) {
        if ((DefaultLogDogConfig.logFilter and priority) == PASS) {
            logPrinter.logPrint(priority, tag, msg)
        }
        if (DefaultLogDogConfig.isWriteLogFileEnable && (DefaultLogDogConfig.logWriteFilter and priority) == PASS) {
            logDiskWrite.logWrite(priority, tag, msg)
        }
    }

    /**
     * 自定义 log 处理
     */
    private fun logDogCustomHandlers(
        printer: Boolean,
        write: Boolean,
        priority: Int,
        tag: String,
        msg: String
    ) {
        if (printer) {
            logPrinter.logPrint(priority, tag, msg)
        }
        if (write) {
            logDiskWrite.logWrite(priority, tag, msg)
        }
    }

    /**
     * 仅供LogDog 内部使用的常量对象
     * 不对外开放 这样可以避免 对外和内部太过于耦合
     * 造成更新后对外部使用造成变动
     */
    companion object {
        const val VERBOSE = 0x01

        const val DEBUG = 0x02

        const val INFO = 0x04

        const val WARN = 0x08

        const val ERROR = 0x10

        const val CRASH = 0x20

        const val ALL = VERBOSE or DEBUG or INFO or WARN or ERROR

        const val PASS = 0x00
        fun build(mContext: Context, jsonEngine: IJsonEngine): ILogDogEngine {
            return LogDogEngine(mContext, jsonEngine)
        }
    }
}